package com.booway.threadtemp.factory;

import java.util.Collection;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.booway.threadtemp.exception.FactoryException;
import com.booway.threadtemp.product.HasHandStock;
import com.booway.threadtemp.stock.StockPackage;

/**
 * S->P的工厂
 * @author cuibo
 *
 * @param <S>
 * @param <P>
 */
public interface IFactory<S, P>
{
    /**
     * 添加原料到工厂
     * @param s
     * @throws FactoryException
     */
    public boolean addStock(S s) throws FactoryException;

    /**
     * 添加原料到工厂
     * @param stockPackage
     * @throws FactoryException
     */
    public boolean addStockPackage(StockPackage<S> stockPackage) throws FactoryException;

    /**
     * 批量添加原料到工厂
     * @param entrys
     * @throws FactoryException
     */
    public boolean addAllStock(Collection<S> entrys) throws FactoryException;

    /**
     * 获取原料对应的产品(设置超时)
     * @param s
     * @param wait
     * @param unit
     * @throws TimeoutException 
     */
    public P getHandleProdct(S s, long wait, TimeUnit unit) throws TimeoutException;

    /**
     * 获取原料对应的产品
     * @param s
     * @return
     */
    public P getHandleProdct(S s);

    /**
     * 获取原料对应的处理完成原料
     * @param s
     * @return
     */
    public HasHandStock<S, P> getHasHandStock(S s);

    /**
     * 获取原料对应的处理完成原料
     * @param s
     * @param wait
     * @param unit
     * @return
     * @throws TimeoutException 
     */
    public HasHandStock<S, P> getHasHandStock(S s, long wait, TimeUnit unit) throws TimeoutException;

    /**
     * 检查原料是否处理完
     * @param s
     * @return
     */
    public boolean checkStockHasDown(S s);

    /**
     * 检查原料包是否处理完
     * @param stockPackageId
     * @return
     */
    public boolean checkStockPackageHasDown(String stockPackageId);

    /**
     * 等待原料加工完成
     * @param s
     * @param wait   等待超时设置
     * @param unit
     * @throws TimeoutException 
     */
    public void waitStockDown(S s, long wait, TimeUnit unit) throws TimeoutException;

    /**
     * 等待原料包加工完成
     * @param stockPackageId
     * @param wait   等待超时设置
     * @param unit
     * @throws TimeoutException 
     */
    public void waitStockPackageDown(String stockPackageId, long wait, TimeUnit unit) throws TimeoutException;

    /**
     * 等待原料包加工完成
     * @param stockPackageId
     */
    public void waitStockPackageDown(String stockPackageId);

    /**
     * 等待原料加工完成（一直等待）
     * @param s
     * @return
     */
    public void waitStockDown(S s);

    /**
     * 等待整个工厂的原料全部完成
     */
    public void waitFactoryDown();

    /**
     * 等待整个工厂的原料全部完成
     * @param wait
     * @param unit
     * @throws TimeoutException 
     */
    public void waitFactoryDown(long wait, TimeUnit unit) throws TimeoutException;

    /**
     * 批量移除原料（如果原料已经送入机器处理则移除失败）
     * @param ts
     * @return  返回移除成功的原料
     */
    public List<S> removeStock(List<S> ts);
    
    /**
     * 批量移除异常原料（如果原料已经送入机器处理则移除失败）
     * @param ts
     * @return  返回移除成功的原料
     */
    public List<S> removeExceptionStock(List<S> ts);
    
    /**
     * 移除指定原料
     * @param s
     * @return
     */
    public boolean removeStock(S s);

    /**
     * 移除指定异常原料
     * @param s
     * @return
     */
    public boolean removeExceptionStock(S s);
    
    /**
     * 重新提交出现异常的原料
     * @return
     * @throws FactoryException 
     */
    public boolean reHandExceptionStock() throws FactoryException;
    
    /**
     * 重新提交出现异常的原料
     * @param s
     * @return
     * @throws FactoryException 
     */
    public boolean reHandExceptionStock(S s) throws FactoryException;

    /**
     * 获取正在等待处理的原料队列
     * @return
     */
    public Queue<S> getWaitingQueue();

    /**
     * 获取正在正在处理的
     * @return
     */
    public Queue<S> getHandingQueue();
    
    /**
     * 获取处理出现异常的原料（持有失败原因）
     * @return
     */
    public Queue<HasHandStock<S, P>> getExceptionQueueWithCause();

    /**
     * 获取处理出现异常的原料
     * @return
     */
    public Queue<S> getExceptionQueue();

    /**
     * 获取已经处理的原料
     * （过期的原料获取不到，应为所有数据均在内存中，不可能无限存储数据，除非持久化）
     * @return
     */
    public Queue<S> getHasHandQueue();

    /**
     * 获取已经处理的原料,并包含其结果信息
     * @return
     */
    public Queue<HasHandStock<S, P>> getHasHandQueueWithProduct();

    /**
     * 暂停工作（已经启动的子线程不会受到影响）
     * @throws FactoryException 
     */
    public void stopHandle() throws FactoryException;

    /**
     * 暂停工作（会将正在运行的子线程也暂停，但是并不能保证暂停成功！）
     * @throws FactoryException 
     */
    public void stopHandleNow() throws FactoryException;

    /**
     * 重启工作
     * @throws FactoryException 
     */
    public void restartHandle() throws FactoryException;

    /**
     * 清除整个工厂
     */
    public void clearFactory();

    /**
     * 关闭
     */
    public void shutDown();
    
    /**
     * 处理原料(模板方法)
     * 该方法不支持抛出异常，在自己实现业务处理时处理自己的异常
     * 虽然机器已经实现了捕获ThrowAble并且自行恢复机器的运行
     * 但实现该业务方法时应要逻辑严谨，尽量不要抛出RuntimeException甚至Error
     * @param s
     * @return
     */
    public P handleStock(S s);
}
